# -*- coding: utf-8 -*-

"""
@author: Laowang
@contact: QQ:1125564921
@Created on: 2022/6/21
@Remark: 
"""

from typing import List
from collections import defaultdict

from .xt_future_client import XTFuture
from .xt_future_utils import public_request_

from framework_strategy.gopy.gateways.settings import XTFUTUREAPISETTING
from framework_strategy.gopy.base import GateWay
from framework_strategy.gopy.base.constant import *
from framework_strategy.gopy.gateways.utils import RequestParamterObj, public_request, \
    ResponseKlineObj, ResponseTickerObj, ResponseOrderBookObj, ResponseTradesObj,\
    ResponseOrderObj, ResponseCancelOrderObj, ResponseBalanceObj, ResponseAccountOrderObj

client = XTFuture(url=XTFUTUREAPISETTING.API_DOMAIN,
        access_key=XTFUTUREAPISETTING.PUBLIC_KEY,
        secret_key=XTFUTUREAPISETTING.SECRET_KEY)


def set_client(access_key, secret_key):
    client = XTFuture(url=XTFUTUREAPISETTING.API_DOMAIN,
        access_key=access_key,
        secret_key=secret_key)
    return client



# ################################################ #
def server_time_response(data, parameter=None):
    """ server time response """
    print("[server_time_response] ", data)
    ndata = dict()
    ndata["data"] = data.get('serverTime')
    return ndata


def market_config_response(data, parameter=None):
    """ account response """
    # print("[account_response] ", data)
    ndata = dict()
    for d in data.get('result'):
        ndata[d.get('symbol')] = {
            "minMoney": None,
            "quotePrecision": d.get('pricePrecision'),
            "quoteAssetPrecision": d.get('quantityPrecision'),
        }
    return {"data": ndata}


def kline_response(data, parameter=None):
    """ kline response """
    ndata = defaultdict(list)
    for d in data.get('result'):
        ndata["data"].append(
            ResponseKlineObj(
                d[0],
                d[1],
                d[2],
                d[3],
                d[4],
                d[5],
            )
        )
    return ndata


def ticker_response(data, parameter=None):
    """ tickers response """
    if not data:
        return data
    ndata = dict()
    ndata = ResponseTickerObj(
        data.get('result').get('bp'),
        None,
        data.get('result').get('ap'),
        None,
        None)
    return {"data": ndata}


def tickers_response(data, parameter=None):
    """ tickers response """
    if not data:
        return data
    ndata = dict()
    for d in data.get('result'):
        ndata[d.get('symbol')] = ResponseTickerObj(
            d.get('bp'),
            None,
            d.get('ap'),
            None,
            None)
    return {"data": ndata}


def depth_response(data, parameter=None):
    """ depth response """
    if not data:
        return data
    ndata = dict()
    ndata["data"] = ResponseOrderBookObj(data.get('result').get('a'), data.get('result').get('b'))
    return ndata


def trades_response(data, parameter=None):
    """ trades response """
    if not data:
        return data
    ndata = defaultdict(list)
    for d in data.get('result'):
        ndata["data"].append(ResponseTradesObj(
            d.get('id'),
            d.get('p'),
            d.get('a'),
            d.get('m'),
            d.get('t')
        ))
    return ndata


def balance_response(data, parameter=None):
    """ balance response """
    if not data:
        return data
    ndata = defaultdict(list)
    for d in data.get('result'):
        ndata["data"].append(
            ResponseBalanceObj(
                d.get('coin'),
                d.get('availableBalance'),
                float(d.get('walletBalance'))-float(d.get('availableBalance')),
            )
        )
    return ndata


def send_order_response(data, parameter=None):
    """ order response """
    if not data:
        # return data
        return ResponseOrderObj(None, None, None, None, None)
    ndata = dict()
    # print("[send_order_response] data ",  data)
    ndata["data"] = ResponseOrderObj(
        data["result"],
        None,
        None,
        None,
        None)
    return ndata


def cancel_order_response(data, parameter=None):
    """ cancel order response """
    if not data:
        return ResponseOrderObj(None, None, None, None, None)
    res = ResponseCancelOrderObj(
        data["result"],
        data["msgInfo"]
    )
    return {"data": res}


def get_order_response(data, parameter=None):
    """ get order response """
    if not data:
        return data
    data = data["result"]
    res = ResponseAccountOrderObj(
        data["origQty"],
        data["price"],
        data["orderId"],
        data["state"],
        data["orderSide"],
        data["orderType"],
    )
    return {"data": res}


def open_order_response(data, parameter=None):
    """ open order response """
    ndata = defaultdict(list)
    if not data:
        return {"data": ndata["data"]}
    for d in data.get('result').get('items'):
        ndata["data"].append(
            ResponseAccountOrderObj(
                d["origQty"],
                d["price"],
                d["orderId"],
                d["status"],
                d["orderSide"],
                d["orderType"])
        )
    return ndata
# ################################################ #


# @public_request(key=public_request_, response_handle=server_time_response)
# def get_server_time(self, event):
#     """ Get server time now """
#     res = client.server_time()
#     res = RequestParamterObj(res, '', event)
#     print("--get_server_time--", self, event, res)
#     return res


@public_request(key=public_request_, response_handle=market_config_response)
def get_all_market_config(self, event):
    """ Access all market config """
    print("--get_all_market_config--", self, event)
    res = client.get_all_market_config()
    res = RequestParamterObj(res, '', event)
    return res


@public_request(key=public_request_, response_handle=kline_response)
def get_klines(self, event):
    """ Get Klines """
    res = client.get_kline(**event.event_data.kwargs)
    print("--get_klines--", res, event)
    res = RequestParamterObj(res, '', event)
    return res


@public_request(key=public_request_, response_handle=ticker_response)
def get_ticker(self, event):
    """ All aggregate market """
    print("--get_tickers--", self, event)
    res = client.get_agg_tiker(**event.event_data.kwargs)
    res = RequestParamterObj(res, '', event)
    return res


@public_request(key=public_request_, response_handle=tickers_response)
def get_tickers(self, event):
    """ All aggregate market """
    print("--get_tickers--", self, event)
    res = client.get_agg_tikers(**event.event_data.kwargs)
    res = RequestParamterObj(res, '', event)
    return res

    
@public_request(key=public_request_, response_handle=depth_response)
def get_depth(self, event):
    """ Gain market depth """
    print("--get_depth--", self, event)
    res = client.get_depth(**event.event_data.kwargs)
    res = RequestParamterObj(res, '', event)
    return res


@public_request(key=public_request_, response_handle=trades_response)
def get_trades(self, event):
    """ Get trade history """
    print("--get_trades--", self, event)
    res = client.get_trades(**event.event_data.kwargs)
    res = RequestParamterObj(res, '', event)
    return res


@public_request(key=public_request_, response_handle=balance_response)
def get_balance(self, event):
    """ Get account info """
    print("--get_account--", self, event)
    client = set_client(event.event_data.kwargs.get('PUBLIC_KEY'), event.event_data.kwargs.get('SECRET_KEY'))
    res = client.get_account_capital()
    res = RequestParamterObj(res, '', event)
    return res


@public_request(key=public_request_, response_handle=send_order_response)
def send_order(self, event):
    """ Order """
    import time
    t0 = time.time()
    # print("--send_order--", self, event)
    client = set_client(event.event_data.kwargs.get('PUBLIC_KEY'), event.event_data.kwargs.get('SECRET_KEY'))
    kwargs = event.event_data.kwargs
    kwargs.pop('PUBLIC_KEY')
    kwargs.pop('SECRET_KEY')
    so_res = client.send_order(**kwargs)
    res = RequestParamterObj(so_res, '', event)
    t1 = time.time()
    print('debug send', so_res, t1-t0)
    return res


@public_request(key=public_request_, response_handle=send_order_response)
def send_orders(self, event):
    """ Order """
    # print("--send_order--", self, event)
    client = set_client(event.event_data.kwargs.get('PUBLIC_KEY'), event.event_data.kwargs.get('SECRET_KEY'))
    res = client.send_batch_order(**event.event_data.kwargs)
    res = RequestParamterObj(res, '', event)
    return res


@public_request(key=public_request_, response_handle=cancel_order_response)
def cancel_order(self, event):
    """ Cancel order """
    import time
    t = time.time()
    # print("--cancel_order--", self, event)
    client = set_client(event.event_data.kwargs.get('PUBLIC_KEY'), event.event_data.kwargs.get('SECRET_KEY'))
    kwargs = event.event_data.kwargs
    kwargs.pop('PUBLIC_KEY')
    kwargs.pop('SECRET_KEY')
    kwargs.pop('symbol')
    kwargs['order_id'] = kwargs.pop('id')
    res = client.cancel_order(**kwargs)
    print('debug cancel', res, "cost::::", time.time() - t)
    res = RequestParamterObj(res, '', event)
    return res


@public_request(key=public_request_, response_handle=cancel_order_response)
def cancel_orders(self, event):
    """ Cancel order """
    print("--cancel_order--", self, event)
    client = set_client(event.event_data.kwargs.get('PUBLIC_KEY'), event.event_data.kwargs.get('SECRET_KEY'))
    res = client.cancel_all_order(**event.event_data.kwargs)
    res = RequestParamterObj(res, '', event)
    return res


@public_request(key=public_request_, response_handle=get_order_response)
def get_order(self, event):
    """ Get order """
    print("--get_order--", self, event)
    client = set_client(event.event_data.kwargs.get('PUBLIC_KEY'), event.event_data.kwargs.get('SECRET_KEY'))
    res = client.get_order_id(**event.event_data.kwargs)
    res = RequestParamterObj(res, '', event)
    return res


@public_request(key=public_request_, response_handle=open_order_response)
def get_open_order(self, event):
    """ Obtain outstanding orders """
    print("--get_open_order--", self, event)
    client = set_client(event.event_data.kwargs.get('PUBLIC_KEY'), event.event_data.kwargs.get('SECRET_KEY'))
    kwargs = event.event_data.kwargs
    kwargs.pop('PUBLIC_KEY')
    kwargs.pop('SECRET_KEY')
    res = client.get_account_order(**kwargs)
    res = RequestParamterObj(res, '', event)
    return res


class XTFUTUREGateway(GateWay):
    exchanges = ["XTFUTURE"]
    def __init__(self, main_engine, event_engine, gateway_name="XTFUTURE", proxy=None) -> None:
        super().__init__(main_engine, event_engine, gateway_name, proxy)

    ON_EVENT: List = [
        (XTFUTURE_EVENT_MARKETCONFIG, get_all_market_config),
        (XTFUTURE_EVENT_KLINE, get_klines),
        (XTFUTURE_EVENT_TICKER, get_ticker),
        (XTFUTURE_EVENT_TICKERS, get_tickers),
        (XTFUTURE_EVENT_MARKETDEPTH, get_depth),
        (XTFUTURE_EVENT_ORDER_TRADE, get_trades),
        (XTFUTURE_EVENT_ACCOUNT_BALANCE, get_balance),
        (XTFUTURE_EVENT_SENDORDER, send_order),
        (XTFUTURE_EVENT_SENDORDERS, send_orders),
        (XTFUTURE_EVENT_CANCELORDER, cancel_order),
        (XTFUTURE_EVENT_CANCELORDERS, cancel_orders),
        (XTFUTURE_EVENT_ORDER_STATUS, get_order),
        (XTFUTURE_EVENT_OPENORDER, get_open_order),
    ]
